// ==UserScript== // @name 2FA TOTP // @namespace 2FA TOTP // @version 0.1.0 // @description 脚本猫后台脚本,一键计算2FA TOTP TOKEN // @author DreamNya // @require https://jiangts.github.io/JS-OTP/dist/jsOTP.min.js#sha256-kduNB64Frzc2wd/FnTAUL1dRIvGOqPwsBlb0Su29Z5w= // @grant GM_setClipboard // @grant GM_notification // @grant GM_getValue // @grant CAT_userConfig // @background // ==/UserScript== /* ==UserConfig== TOTP设置: Clipboard: title: 是否自动复制TOTP到剪贴板 default: '复制' type: select values: ['复制','不复制'] Notify: title: 是否通知TOTP结果 default: '通知' type: select values: ['通知','不通知'] NotifyTitle: title: 通知标题 description: 可选,留空代表默认标题 type: text NotifyTimeout: title: 通知持续时间 description: 默认5000ms,最小1000ms type: number default: 5000 min: 1000 unit: ms Secret: title: TOTP Secret Key description: 明文存储在脚本猫本地,脚本无任何通讯功能 type: text ==/UserConfig== */ const userConfig = {}; Object.entries(GM_info.userConfig).forEach(([mainKey, configs]) => { Object.entries(configs).forEach(([subKey, { default: defaultValue, type }]) => { const value = GM_getValue(`${mainKey}.${subKey}`, defaultValue); if (type == "select") { userConfig[subKey] = value == defaultValue; } else { userConfig[subKey] = value; } }); }); userConfig.FormatNotifyTitle = (userConfig.NotifyTitle ? userConfig.NotifyTitle : "") + " TOTP "; return new Promise((resolve, reject) => { try { const totp = new jsOTP.totp(); const timeCode = totp.getOtp(userConfig.Secret); userConfig.Clipboard && GM_setClipboard(timeCode); userConfig.Notify && GM_notification({ title: userConfig.FormatNotifyTitle + (userConfig.Clipboard ? "已复制" : ""), text: timeCode, timeout: userConfig.NotifyTimeout, }); resolve(); } catch (err) { console.error(err); GM_notification({ title: userConfig.FormatNotifyTitle + "错误", text: err.message, }); reject(err.message); } });